#pragma once
#include <glm/glm.hpp>
#include <thread>
#include <fstream>
#include "core/cbase.h"
#include "core/CColor.h"
#include "Enum.h"
#include "Project/Proj.h"

#define W3D Config::View3D_W
#define H3D Config::View3D_H
#define SSAA Config::Render_SurfaceSSAA// a float type

#ifdef __QT__
	static const CString EmbedEnv_Main_Qml_Path = "res3D/asset/qml/Main3D.qml";
#endif

static const CString EmbedEnv_Config_File_Path = "res3D/asset/cfg/config.lua";

/** Initialization of static member variables will be completed before the main() function is executed! **/
class Config {
public:
	static bool Released;
	static CString BuildTime;

	static bool TestCase_SampleDataEnabled;
	static int TestCase_SampleDataLoopIntervalMs;

	static int Version_Code;
	static CString Version_CachePath;
	static bool Enable_Log;

	static int Mechanism_ExpireUpdateCnt;
	static int Mechanism_ExpireFrameCnt;

	static int View3D_W;
	static int View3D_H;
	static int View3D_SkylineFromTopPx;
	static int View3D_FadeOffsetHorizonPx;
	static int View3D_FadeOffsetSkylinePx;
	static CString View3D_BgLightImgPath;
	static CString View3D_BgDarkImgPath;
	static CString View3D_ZhichePngPath;
	static CString View3D_ZhicheInfoPath;
	static float View3D_ZhichePngOccupationWRate;
	static float View3D_ZhichePngOccupationHRate;

	static CColor Render_ClearColor;

	static float Render_SurfaceSSAA;
	static int Render_SurfaceSamples;

	static float Camera_ViewScale;
	static Vec3 Camera_Position;
	static float Camera_PitchAngle;
	static float Camera_FOV;
	static float Camera_YawAngle;
	static float Camera_NearPlane;
	static float Camera_FarPlane;

	static Vec3 Light_Directional_WorldDirection;
	static float Light_Directional_Intensity;
	static CColor Light_Directional_Color;

	static Vec3 Light_Point_Position;
	static float Light_Point_Intensity;
	static float Light_Point_ConstAtt;
	static float Light_Point_LinearAtt;
	static float Light_Point_QuadAtt;
	static CColor Light_Point_Color;

	static bool Material_ForceUseCfgValue;
	static float Material_Metallic;
	static float Material_Roughness;
	static CColor Material_BaseColor;
	static float Material_PBRGlobalAmbientCompnt;

	static CString Shader_Dir;
	static CString Shader_Line;
	static CString Shader_ModelPBR;
	static CString Shader_AnyFree;
	static CString Shader_AnyFreeAlpha;
	static CString Shader_AccFD;
	static CString Shader_AccTG;
	static CString Shader_LampLight;
	static CString Shader_LineEllipse;
	static CString Shader_DclcArrow;
	static CString Shader_RoadDotBg;
	static CString Shader_LaneBg;
	static CString Shader_RoadEdge;
	static CString Shader_SceneTexture;
	static CString Shader_ActiveCircle;
	static CString Shader_ModelTexture;

	static bool Line_CutOff_ByEqStart;
	static bool Line_CutOff_ByEqEnd;
	static int Line_FadeByEndZOffsetPx;
	static CColor Line_DefColor;
	static CColor Line_DefGrey;
	static float Line_PointsZStep;
	static float Line_Width;
	static float Line_HInterval;
	static float Line_VSpeedFactor;
	static float Line_Dashed_SegLen;
	static float Line_Dashed_SegInterval;
	static float Line_RoadEdgeDashed_SegLen;
	static float Line_RoadEdgeDashed_SegInterval;
	static float Line_RoadEdge_Width;
	static float Line_RoadEdge_Height;
	static CColor Line_RoadEdge_UpColor;
	static CColor Line_RoadEdge_SideColor;
	static RoadEdgeStyle Line_RoadEdge_Style;

	static float Model_Scale;
	static CString Model_Dir;
	static CString Model_Zhiche;
	static CString Model_Car;
	static CString Model_Bus;
	static CString Model_Truck;
	static CString Model_Moto;
	static CString Model_Bike;
	static CString Model_Cone;
	static CString Model_Person;
	static CString Model_Barrier;
	static CString Model_Undefined;

	static float Marker_AccFD_FrontOffsetD;
	static float Marker_AccFD_TopWByFrontWTimes;
	static float Marker_AccFD_BottomWByFrontWTimes;
	static float Marker_AccFD_HByFrontWTimes;
	static CColor Marker_AccTG_Color;
	static float Marker_ACCTG_ZhicheHeadOffsetD;
	static float Marker_AccTG_WByZhicheWTimes;
	static float Marker_AccTG_RectHByZhicheWTimes;
	static float Marker_AccTG_RectIntervalByZhicheWTimes;
	static float Marker_Lamp_LightRadiusByModelWTimes;
	static CColor Marker_Lamp_TurnColor;
	static CColor Marker_Lamp_BrakeColor;
	static float Marker_Ellipse_CenterZ;
	static float Marker_Ellipse_HAxis;
	static float Marker_Ellipse_VAxis;
	static CColor Marker_Ellipse_ColorNormal;
	static CColor Marker_Ellipse_ColorWarning;
	static int Marker_Ellipse_BlinkFrameGap;
	static float Marker_DclcArrow_ZStart;
	static float Marker_DclcArrow_ZRectEnd;
	static float Marker_DclcArrow_ZBezierEnd;
	static float Marker_DclcArrow_ZEndBelowSkyline;
	static float Marker_DclcArrow_EdgeW;
	static float Marker_DclcArrow_RectWByZhicheWTimes;
	static float Marker_DclcArrow_OffsetWPercentage;
	static CColor Marker_DclcArrow_Color;
	static float Marker_RoadBg_DotRadius;
	static float Marker_RoadBg_DotIntervalH;
	static float Marker_RoadBg_DotIntervalV;
	static float Marker_RoadBg_PointsZStep;
	static CColor Marker_RoadBg_LightColor;
	static CColor Marker_RoadBg_DarkColor;
	static RoadBgStyle Marker_RoadBg_Style;
	static int Marker_ActiveCircle_BreathFrameGap;
	static float Marker_ActiveCircle_Radius;

	static float Y_RoadBg;
	static float Y_Line;
	static float Y_ActiveCircle;
	static float Y_Model;
	static float Y_Ellipse;
	static float Y_DclcArrow;
	static float Y_AccFD;
	static float Y_AccTG;

	/**@note before using other method, call it first!*/
	static void init() {
		readConfigFields();
	}

	static void resize3DView(int width, int height) {
		View3D_W = width;
		View3D_H = height;
	}

	static CString modelPath(ModelType modelType) {
		CString modelName;
		switch (modelType) {
			case ModelType::Zhiche: modelName = Model_Zhiche; break;
			case ModelType::Car: modelName = Model_Car; break;
			case ModelType::Bus: modelName = Model_Bus; break;
			case ModelType::Truck: modelName = Model_Truck; break;
			case ModelType::Moto: modelName = Model_Moto; break;
			case ModelType::Bike: modelName = Model_Bike; break;
			case ModelType::Cone: modelName = Model_Cone; break;
			case ModelType::Person: modelName = Model_Person; break;
			case ModelType::Barrier: modelName = Model_Barrier; break;
			case ModelType::Undefined:
			case ModelType::Unknown: modelName = Model_Undefined; break;
			default: break;// ModelType::Unknown is not handled
		}
		ASSERT(!modelName.empty(), CString("wrong ModelType: can not be parsed! modelType = ").append(static_cast<int>(modelType)).c_str());
		return Model_Dir + "/" + modelName;
	}

	static CString shaderPath(ShaderType shaderType, const CString& shaderName) {
		CString fileName;
		switch(shaderType) {
			case ShaderType::VertexShader: fileName = shaderName.arg(".vert"); break;
			case ShaderType::FragmentShader: fileName = shaderName.arg(".frag"); break;
			case ShaderType::GeometryShader: fileName = shaderName.arg(".geom"); break;
			default: break;// ShaderType::ComputeShader is not handled
		}
		auto path = Shader_Dir + "/" + fileName;
		std::ifstream infile(path);
		if (ShaderType::GeometryShader == shaderType && !infile.good())
			return "";
		return path;
	}

	#ifdef __QT__
	static CString MainQmlPath() { return getLocalEnvPath(EmbedEnv_Main_Qml_Path); }

	static CString getQmlRelativeLocalEnvPath(CString path) {
		if (IsEnv_Linux) {
			if (Proj::isSQZK())
				path.replace("res/res3D/asset", "..");
			else
				path.replace("res3D/asset", "..");
		} else
			path.replace("../res", "..");
		return path;
	}
	#endif

private:
	static void toLocalEnvPath(CString& path) {
		if (IsEnv_Linux) {
			if (Proj::isSQZK())
				path.replace("res3D", "res/res3D");
			return;
		}
		path.replace("res3D/asset", "../res");
	}

	static CString getLocalEnvPath(CString path) {
		toLocalEnvPath(path);
		return path;
	}

	static void readConfigFields();
};